<!DOCTYPE html>
<html>
  <head>
    <title>threejs</title>
    <style>
      body {
        padding: 0;
        margin: 0;
      }

      canvas {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>

  <body ontouchmove="event.preventDefault()"></body>
  <script type="module">
    import * as THREE from "https://cdn.skypack.dev/three@v0.129.0";
    import { OrbitControls } from "https://cdn.skypack.dev/three@v0.129.0/examples/jsm/controls/OrbitControls.js";
    import { EffectComposer } from "https://cdn.skypack.dev/three@v0.129.0/examples/jsm/postprocessing/EffectComposer.js";
    import { RenderPass } from "https://cdn.skypack.dev/three@v0.129.0/examples/jsm/postprocessing/RenderPass.js";
    import { ShaderPass } from "https://cdn.skypack.dev/three@v0.129.0/examples/jsm/postprocessing/ShaderPass.js";
    import { UnrealBloomPass } from "https://cdn.skypack.dev/three@v0.129.0/examples/jsm/postprocessing/UnrealBloomPass.js";

    // 创建渲染器对象
    var renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio); // 设置像素比
    document.body.appendChild(renderer.domElement); //body元素中插入canvas对象

    // 创建场景对象
    var scene = new THREE.Scene();
    scene.background = new THREE.Color("#347897");

    // 创建相机
    const far = 500000;
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, far);
    camera.position.set(0, 100, 100);

    // 点光源
    var point = new THREE.PointLight("#fff", 1);
    point.position.set(40, 200, 300); // 点光源位置
    scene.add(point); // 点光源添加到场景中

    // 环境光
    var ambient = new THREE.AmbientLight("#fff", 0.4);
    scene.add(ambient);

    // 添加辅助线
    const axisHelper = new THREE.AxisHelper(500);
    scene.add(axisHelper);

    // 创建控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.autoRotate = true;

    // 创建两个立方体
    for (let i = 0; i < 2; i++) {
      let g = i == 0 ? new THREE.BoxGeometry(50, 50, 50, 100) : new THREE.TorusGeometry(80, 3, 16, 100);
      let m = new THREE.MeshStandardMaterial({ color: i == 0 ? "#ffff00" : "#ff00ff", side: THREE.DoubuleSide });
      let box = new THREE.Mesh(g, m);
      box.position.set(...(i == 0 ? [0, 0, 0] : [0, 0, -60]));
      i == 1 && box.layers.enable(31);
      scene.add(box);
    }

    // 创建unreal辉光合成器
    const unrealBloomComposer = new EffectComposer(renderer);
    unrealBloomComposer.renderToScreen = false;
    // 创建渲染通道
    const renderPass = new RenderPass(scene, camera); 
    unrealBloomComposer.addPass(renderPass); 
    // 创建unreal辉光通道
    const unrealBloomPass = new UnrealBloomPass();
    unrealBloomPass.threshold = 0.0; // 阈值，
    unrealBloomPass.strength = 2.1; // 强度
    unrealBloomPass.radius = 1; // 范围
    unrealBloomComposer.addPass(unrealBloomPass); 

    // 创建主合成器
    const masterComposer = new EffectComposer(renderer);
    const renderPass1 = new RenderPass(scene, camera);
    masterComposer.addPass(renderPass1); 
    // 创建自定义通道
    const shaderPass = new ShaderPass(
      new THREE.ShaderMaterial({
        uniforms: {
          baseTexture: { value: null }, 
          bloomTexture: { value: unrealBloomComposer.renderTarget2.texture }, 
        },
        vertexShader: `
    	  varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }
      `,
        fragmentShader: `
        uniform sampler2D baseTexture;
        uniform sampler2D bloomTexture; 
        varying vec2 vUv; 
        void main() {
          gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
        }
      `,
        defines: {},
      }),
      "baseTexture"
    );
    masterComposer.addPass(shaderPass);

    // 渲染
    requestAnimationFrame(function render() {
      requestAnimationFrame(render);
      controls.update(); // 更新控制器
      //renderer.render(scene, camera);

      // 先创建一个黑色的材质
      const darkMaterial = new THREE.MeshBasicMaterial({
        color: "#000",
      });

      // 渲染辉光
      !(function () {
        scene.traverse((obj) => {
          const layers = new THREE.Layers(); 
          layers.set(31);
          if (!obj.layers.test(layers)) {
            obj._material = obj.material;
            obj.material = darkMaterial; // 应用黑色材质
          }
        });
        // 背景也设置为黑色
        scene._background = scene.background;
        scene.background = new THREE.Color("#000");
        // 渲染辉光效果
        unrealBloomComposer.render();
        // 场景背景色还原
        scene.background = scene._background;
        // 物体材质还原
        scene.traverse((obj) => {
          const layers = new THREE.Layers();
          layers.set(31);
          if (!obj.layers.test(layers)) {
            obj._material && (obj.material = obj._material) && (obj._material = null);
          }
        });
      })();

      // 渲染主合成器
      !(function () {
        scene.traverse((obj) => {
          const layers = new THREE.Layers();
          layers.set(31);
          if (obj.layers.test(layers)) {
            obj._material = obj.material;
            obj.material = darkMaterial;
          }
        });
        masterComposer.render();
        // 物体材质还原
        scene.traverse((obj) => {
          const layers = new THREE.Layers();
          layers.set(31);
          if (obj.layers.test(layers)) {
            obj._material && (obj.material = obj._material) && (obj._material = null);
          }
        });
      })();
    });
  </script>
</html>
